package poo.biblioteca.bd;

import biblioteca.entidades.*;
import biblioteca.excepciones.ExcepcionDeBD;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import poo.biblioteca.utilidades.UtlManejadorImagenes;

public class BDLibros {

    DBManager dbm = null;
    UtlManejadorImagenes utlManejadorImagenes = new UtlManejadorImagenes();

    //<editor-fold defaultstate="collapsed" desc="Genero">
    public ArrayList<Genero> buscarGeneroPorNombre(String nombre) throws ExcepcionDeBD {
        ArrayList<Genero> coincidencias = new ArrayList<>();
        nombre = "%" + nombre + "%";

        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pstm = conn.prepareStatement(
                    "SELECT IDGENERO, NOMBREGENERO FROM GENERO "
                    + "WHERE NOMBREGENERO LIKE ?");

            pstm.setString(1, nombre);
            ResultSet rs = pstm.executeQuery();
            Genero genero = null;
            while (rs.next()) {
                genero = new Genero(rs.getInt(1), rs.getString(2));
                coincidencias.add(genero);
            }
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo leer los registros "
                    + "de Géneros", ex);
        }

        return coincidencias;
    }

    public Genero buscarGeneroPorId(int idGenero) throws ExcepcionDeBD {
        Genero genero = new Genero();

        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pstm = conn.prepareStatement(
                    "SELECT IDGENERO, NOMBREGENERO FROM GENERO "
                    + "WHERE IDGENERO LIKE ?");

            pstm.setInt(1, idGenero);
            ResultSet rs = pstm.executeQuery();

            while (rs.next()) {
                genero = new Genero(rs.getInt(1), rs.getString(2));
            }
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo leer los registros "
                    + "de Géneros", ex);
        }

        return genero;
    }

    public void registrarGenero(Genero nuevoGenero) throws ExcepcionDeBD {
        dbm = DBManager.getInstancia();
        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "INSERT INTO GENERO (NOMBREGENERO) VALUES (?)");
            pst.setString(1, nuevoGenero.getNombreGenero());
            pst.executeUpdate();
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo registrar el Género "
                    + nuevoGenero.getNombreGenero() + " en la Base de Datos");
        }
    }

    public void eliminarGenero(Genero generoSeleccionado) throws ExcepcionDeBD {
        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "SELECT COUNT(*) FROM LIBRO WHERE IDGENERO = ?;");
            pst.setInt(1, generoSeleccionado.getIdGenero());
            ResultSet rs = pst.executeQuery();
            rs.next();

            if (rs.getInt(1) > 0) {
                throw new ExcepcionDeBD("No se pueden eliminar Géneros que "
                        + "están asociados a libros registrados");
            }
        } catch (SQLException ex) {

            throw new ExcepcionDeBD("No se pudo acceder a la Base de Datos");
        }

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "DELETE FROM GENERO WHERE IDGENERO = ?");
            pst.setInt(1, generoSeleccionado.getIdGenero());
            pst.executeUpdate();
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo eliminar el Género");
        }
    }

    public void modificarGenero(Genero generoSeleccionado) throws ExcepcionDeBD {
        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "UPDATE GENERO SET NOMBREGENERO = ? WHERE "
                    + "IDGENERO = ?");
            pst.setString(1, generoSeleccionado.getNombreGenero());
            pst.setInt(2, generoSeleccionado.getIdGenero());
            pst.executeUpdate();

        } catch (SQLException ex) {
            //System.out.println(ex.getMessage());
            throw new ExcepcionDeBD("No se pudo acceder a la Base de Datos");
        }

    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Pais">
    public ArrayList<Pais> listarPaises() throws ExcepcionDeBD {
        ArrayList<Pais> coincidencias = new ArrayList<>();

        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("SELECT IDPAIS, NOMBREPAIS FROM PAIS");
            Pais pais = null;
            while (rs.next()) {
                pais = new Pais(rs.getInt(1), rs.getString(2));
                coincidencias.add(pais);
            }
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo leer los registros "
                    + "de Países", ex);
        }

        return coincidencias;
    }

    private Pais buscarPaisPorId(int idPais) throws ExcepcionDeBD {
        Pais coincidencia = new Pais();

        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pstm = conn.prepareStatement(
                    "SELECT NOMBREPAIS FROM PAIS "
                    + "WHERE IDPAIS LIKE ?");

            pstm.setInt(1, idPais);
            ResultSet rs = pstm.executeQuery();
            Pais pais = null;
            rs.next();
            coincidencia = new Pais(idPais, rs.getString(1));


        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo leer los registros "
                    + "de Pais", ex);
        }

        return coincidencia;
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Editorial">
    public void registrarEditorial(Editorial nuevaEditorial) throws ExcepcionDeBD {
        dbm = DBManager.getInstancia();
        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "INSERT INTO EDITORIAL (NOMBREEDITORIAL, IDPAIS) VALUES (?,?)");
            pst.setString(1, nuevaEditorial.getNombreEditorial());
            pst.setInt(2, nuevaEditorial.getPais().getIdPais());
            pst.executeUpdate();
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo registrar la Editorial "
                    + nuevaEditorial.getNombreEditorial() + " en la Base de Datos");
        }
    }

    public ArrayList<Editorial> buscarEditorialPorNombre(String nombreEditorial) throws ExcepcionDeBD {
        ArrayList<Editorial> coincidencias = new ArrayList<>();
        nombreEditorial = "%" + nombreEditorial + "%";

        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pstm = conn.prepareStatement(
                    "SELECT IDEDITORIAL, NOMBREEDITORIAL, IDPAIS FROM EDITORIAL "
                    + "WHERE NOMBREEDITORIAL LIKE ?");

            pstm.setString(1, nombreEditorial);
            ResultSet rs = pstm.executeQuery();
            Editorial editorial = null;
            while (rs.next()) {
                editorial = new Editorial(rs.getInt(1), rs.getString(2), buscarPaisPorId(rs.getInt(3)));
                coincidencias.add(editorial);
            }
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo leer los registros "
                    + "de Editoriales", ex);
        }

        return coincidencias;
    }

    public Editorial buscarEditorialPorId(int idEditorial) throws ExcepcionDeBD {
        Editorial coincidencia = new Editorial();

        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pstm = conn.prepareStatement(
                    "SELECT IDEDITORIAL, NOMBREEDITORIAL, IDPAIS FROM EDITORIAL "
                    + "WHERE IDEDITORIAL LIKE ?");

            pstm.setInt(1, idEditorial);
            ResultSet rs = pstm.executeQuery();

            while (rs.next()) {
                coincidencia = new Editorial(rs.getInt(1), rs.getString(2), buscarPaisPorId(rs.getInt(3)));
            }
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo leer los registros "
                    + "de Editoriales", ex);
        }

        return coincidencia;
    }

    public void eliminarEditorial(Editorial editorialSeleccionada) throws ExcepcionDeBD {
        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "SELECT COUNT(*) FROM LIBRO WHERE IDEDITORIAL = ?;");
            pst.setInt(1, editorialSeleccionada.getIdEditorial());
            ResultSet rs = pst.executeQuery();
            rs.next();

            if (rs.getInt(1) > 0) {
                throw new ExcepcionDeBD("No se pueden eliminar Editoriales que "
                        + "estén asociados a libros registrados");
            }
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo acceder a la Base de Datos");
        }

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "DELETE FROM EDITORIAL WHERE IDEDITORIAL = ?");
            pst.setInt(1, editorialSeleccionada.getIdEditorial());
            pst.executeUpdate();
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo eliminar la Editorial");
        }
    }

    public void modificarEditorial(Editorial editorialSeleccionada) throws ExcepcionDeBD {
        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "UPDATE EDITORIAL SET NOMBREEDITORIAL = ?, IDPAIS = ? WHERE "
                    + "IDEDITORIAL = ?");
            pst.setString(1, editorialSeleccionada.getNombreEditorial());
            pst.setInt(2, editorialSeleccionada.getPais().getIdPais());
            pst.setInt(3, editorialSeleccionada.getIdEditorial());
            pst.executeUpdate();

        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo acceder a la Base de Datos");
        }
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Autor">
    public ArrayList<Autor> buscarAutorPorNombreYApellido(String nombreAutor, String apellidoAutor) throws ExcepcionDeBD {
        ArrayList<Autor> coincidencias = new ArrayList<>();

        nombreAutor = "%" + nombreAutor + "%";
        apellidoAutor = "%" + apellidoAutor + "%";

        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pstm = conn.prepareStatement(
                    "SELECT IDAUTOR, NOMBREAUTOR, APELLIDOAUTOR, IDPAIS FROM AUTOR "
                    + "WHERE NOMBREAUTOR LIKE ? AND APELLIDOAUTOR LIKE ?");

            pstm.setString(1, nombreAutor);
            pstm.setString(2, apellidoAutor);
            ResultSet rs = pstm.executeQuery();
            Autor autor = null;
            while (rs.next()) {
                autor = new Autor(rs.getInt(1), rs.getString(2), rs.getString(3), buscarPaisPorId(rs.getInt(4)));
                coincidencias.add(autor);
            }
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo leer los registros "
                    + "de Autores", ex);
        }

        return coincidencias;
    }

    public ArrayList<Autor> buscarAutoresDeLibro(int idLibro) throws ExcepcionDeBD {
        ArrayList<Autor> coincidencias = new ArrayList<>();

        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pstm = conn.prepareStatement(
                    "SELECT AUTOR.IDAUTOR, NOMBREAUTOR, APELLIDOAUTOR, IDPAIS "
                    + "FROM AUTOR JOIN AUTORDELIBRO "
                    + "ON (AUTOR.IDAUTOR = AUTORDELIBRO.IDAUTOR) "
                    + "WHERE AUTORDELIBRO.IDLIBRO = ?");

            pstm.setInt(1, idLibro);

            ResultSet rs = pstm.executeQuery();
            Autor autor = null;
            while (rs.next()) {
                autor = new Autor(rs.getInt(1), rs.getString(2), rs.getString(3), buscarPaisPorId(rs.getInt(4)));
                coincidencias.add(autor);
            }
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo leer los registros "
                    + "de Autores", ex);
        }

        return coincidencias;
    }

    public void registrarAutor(Autor nuevoAutor) throws ExcepcionDeBD {
        dbm = DBManager.getInstancia();
        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "INSERT INTO AUTOR (NOMBREAUTOR, APELLIDOAUTOR, IDPAIS) "
                    + "VALUES (?,?,?)");
            pst.setString(1, nuevoAutor.getNombreAutor());
            pst.setString(2, nuevoAutor.getApellidoAutor());
            pst.setInt(3, nuevoAutor.getPais().getIdPais());
            pst.executeUpdate();
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo registrar el Autor "
                    + nuevoAutor.getNombreAutor() + " "
                    + nuevoAutor.getApellidoAutor() + " en la Base de Datos");
        }
    }

    public void eliminarAutor(Autor autorSeleccionado) throws ExcepcionDeBD {
        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "SELECT COUNT(*) FROM AUTORDELIBRO WHERE IDAUTOR = ?;");
            pst.setInt(1, autorSeleccionado.getIdAutor());
            ResultSet rs = pst.executeQuery();
            rs.next();

            if (rs.getInt(1) > 0) {
                throw new ExcepcionDeBD("No se pueden eliminar Autores que "
                        + "estén asociados a libros registrados");
            }
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo acceder a la Base de Datos");
        }

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "DELETE FROM AUTOR WHERE IDAUTOR = ?");
            pst.setInt(1, autorSeleccionado.getIdAutor());
            pst.executeUpdate();
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo eliminar el Autor");
        }
    }

    public void modificarAutor(Autor autorSeleccionado) throws ExcepcionDeBD {
        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "UPDATE AUTOR SET NOMBREAUTOR = ?, APELLIDOAUTOR = ?,"
                    + " IDPAIS = ? WHERE "
                    + "IDAUTOR = ?");
            pst.setString(1, autorSeleccionado.getNombreAutor());
            pst.setString(2, autorSeleccionado.getApellidoAutor());
            pst.setInt(3, autorSeleccionado.getPais().getIdPais());
            pst.setInt(4, autorSeleccionado.getIdAutor());
            pst.executeUpdate();

        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo acceder a la Base de Datos");
        }
    }

    //</editor-fold>
    //<editor-fold defaultstate="collapsed" desc="Libro">
    public void registrarLibro(Libro nuevoLibro) throws ExcepcionDeBD {
        dbm = DBManager.getInstancia();
        Connection conn;
        try {
            conn = dbm.getConnection();
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo conseguir una conexión con la Base de Datos");
        }
        try {
            conn.setAutoCommit(false);
            PreparedStatement pst;
            if (nuevoLibro.getArchivoPortada() != null) {
                pst = conn.prepareStatement(
                        "INSERT INTO LIBRO (ISBN, TITULO, EDICION, PORTADA, "
                        + "IDEDITORIAL, IDGENERO) "
                        + "VALUES (?,?,?,?,?,?)", Statement.RETURN_GENERATED_KEYS);
                pst.setString(1, nuevoLibro.getIsbn());
                pst.setString(2, nuevoLibro.getTitulo());
                pst.setInt(3, nuevoLibro.getEdicion());
                pst.setBlob(4, new FileInputStream(nuevoLibro.getArchivoPortada()), nuevoLibro.getArchivoPortada().length());
                pst.setInt(5, nuevoLibro.getEditorial().getIdEditorial());
                pst.setInt(6, nuevoLibro.getGenero().getIdGenero());
            } else {
                pst = conn.prepareStatement(
                        "INSERT INTO LIBRO (ISBN, TITULO, EDICION, "
                        + "IDEDITORIAL, IDGENERO) "
                        + "VALUES (?,?,?,?,?)", Statement.RETURN_GENERATED_KEYS);
                pst.setString(1, nuevoLibro.getIsbn());
                pst.setString(2, nuevoLibro.getTitulo());
                pst.setInt(3, nuevoLibro.getEdicion());
                pst.setInt(4, nuevoLibro.getEditorial().getIdEditorial());
                pst.setInt(5, nuevoLibro.getGenero().getIdGenero());
            }

            pst.executeUpdate();

            ResultSet rs = pst.getGeneratedKeys();
            int idGenerado = -1;
            while (rs.next()) {
                idGenerado = rs.getInt(1);
            }

            rs.close();

            for (Autor autor : nuevoLibro.getAutores()) {
                pst = conn.prepareStatement(
                        "INSERT INTO AUTORDELIBRO (IDAUTOR, IDLIBRO) "
                        + "VALUES (?,?)");
                pst.setInt(1, autor.getIdAutor());
                pst.setInt(2, idGenerado);

                pst.executeUpdate();
            }
            conn.commit();
        } catch (FileNotFoundException ex) {
            try {
                conn.rollback();
            } catch (SQLException ex1) {
                throw new ExcepcionDeBD("Hubo un problema al intentar deshacer "
                        + "el registro en la Base de Datos");
            }
            throw new ExcepcionDeBD("No se pudo registrar la portada del libro");
        } catch (SQLException ex) {
            try {
                conn.rollback();
            } catch (SQLException ex1) {
                throw new ExcepcionDeBD("Hubo un problema al intentar deshacer "
                        + "el registro en la Base de Datos");
            }
            throw new ExcepcionDeBD("No se pudo registrar el Libro"
                    + " en la Base de Datos");
        } finally {
            try {
                conn.close();
            } catch (SQLException ex) {
                throw new ExcepcionDeBD("No se pudo cerrar correctamente la "
                        + " conexión con la Base de Datos");
            }
        }
    }

    public ArrayList<Libro> buscarLibro(String isbn, String titulo,
            Editorial editorial, Genero genero) throws ExcepcionDeBD {

        ArrayList<Libro> coincidencias = new ArrayList<>();
        dbm = DBManager.getInstancia();
        Connection conn;

        try {
            conn = dbm.getConnection();
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo conseguir una conexión con la Base de Datos");
        }

        StringBuilder criterioDeBusqueda = new StringBuilder("SELECT IDLIBRO, ISBN, TITULO, EDICION, "
                + "PORTADA, IDEDITORIAL, IDGENERO FROM LIBRO WHERE ");

        int argumentos = 0;

        boolean hayISBN = false, hayTitulo = false,
                hayEditorial = false, hayGenero = false;

        if (isbn != null) {
            criterioDeBusqueda.append("ISBN LIKE ?");
        }
        if (titulo != null) {
            if (criterioDeBusqueda.toString().endsWith("?")) {
                criterioDeBusqueda.append(" AND TITULO LIKE ?");
            } else {
                criterioDeBusqueda.append("TITULO LIKE ?");
            }
        }
        if (editorial != null) {
            if (criterioDeBusqueda.toString().endsWith("?")) {
                criterioDeBusqueda.append(" AND IDEDITORIAL = ?");
            } else {
                criterioDeBusqueda.append("IDEDITORIAL = ?");
            }
        }
        if (genero != null) {
            if (criterioDeBusqueda.toString().endsWith("?")) {
                criterioDeBusqueda.append(" AND IDGENERO = ?");
            } else {
                criterioDeBusqueda.append("IDGENERO = ?");
            }
        }

        PreparedStatement pst;
        try {
            pst = (PreparedStatement) conn.prepareStatement(
                    criterioDeBusqueda.toString());
            if (isbn != null) {
                pst.setString(++argumentos, "%" + isbn + "%");
            }
            if (titulo != null) {
                pst.setString(++argumentos, "%" + titulo + "%");
            }
            if (editorial != null) {
                pst.setInt(++argumentos, editorial.getIdEditorial());
            }
            if (genero != null) {
                pst.setInt(++argumentos, genero.getIdGenero());
            }
            //
            ResultSet rs = pst.executeQuery();
            Libro libro;
            while (rs.next()) {
                InputStream is = rs.getBinaryStream("portada");
                ImageIcon portada = null;
                if (is != null) {
                    try {
                        BufferedImage image = ImageIO.read(is);
                        portada = new ImageIcon(image);
                    } catch (IOException ex) {
                    }
                }
                int idLibro = rs.getInt(1);
                libro = new Libro(
                        idLibro, //idlibro
                        rs.getString(2), //isbn
                        rs.getString(3), //titulo
                        rs.getInt(4), //edicion 
                        portada, //portada 
                        buscarEditorialPorId(rs.getInt(6)), //editorial 
                        buscarGeneroPorId(rs.getInt(7)), //genero 
                        buscarAutoresDeLibro(idLibro)); //autores
                coincidencias.add(libro);
            }
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo acceder a la información de Libros");
        }

        return coincidencias;

    }

    public void eliminarLibro(Libro libroSeleccionado) throws ExcepcionDeBD {
        dbm = DBManager.getInstancia();

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "SELECT COUNT(*) FROM EJEMPLAR WHERE IDLIBRO = ?;");
            pst.setInt(1, libroSeleccionado.getIdLibro());
            ResultSet rs = pst.executeQuery();
            rs.next();

            if (rs.getInt(1) > 0) {
                throw new ExcepcionDeBD("No se pueden eliminar Libros que "
                        + "estén asociados a ejemplares existentes");
            }
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo acceder a la Base de Datos");
        }

        try (Connection conn = dbm.getConnection()) {
            PreparedStatement pst = conn.prepareStatement(
                    "DELETE FROM LIBRO WHERE IDLIBRO = ?");
            pst.setInt(1, libroSeleccionado.getIdLibro());
            pst.executeUpdate();
        } catch (SQLException ex) {
            System.out.println(ex.getMessage());
            throw new ExcepcionDeBD("No se pudo eliminar el Libro");
        }

    }

    public void modificarLibro(Libro nuevoLibro) throws ExcepcionDeBD {

        dbm = DBManager.getInstancia();
        Connection conn;
        try {
            conn = dbm.getConnection();
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo conseguir una conexión con la Base de Datos");
        }
        try {
            conn.setAutoCommit(false);
            PreparedStatement pst;
            if (nuevoLibro.getArchivoPortada() != null) {
                pst = conn.prepareStatement(
                        "UPDATE LIBRO SET ISBN = ?, TITULO = ?, EDICION = ?, PORTADA = ?, "
                        + "IDEDITORIAL = ?, IDGENERO = ? WHERE IDLIBRO = ?");
                pst.setString(1, nuevoLibro.getIsbn());
                pst.setString(2, nuevoLibro.getTitulo());
                pst.setInt(3, nuevoLibro.getEdicion());
                pst.setBlob(4, new FileInputStream(nuevoLibro.getArchivoPortada()), nuevoLibro.getArchivoPortada().length());
                pst.setInt(5, nuevoLibro.getEditorial().getIdEditorial());
                pst.setInt(6, nuevoLibro.getGenero().getIdGenero());
                pst.setInt(7, nuevoLibro.getIdLibro());
            } else {
                pst = conn.prepareStatement(
                        "UPDATE LIBRO SET ISBN = ?, TITULO = ?, EDICION = ?, "
                        + "IDEDITORIAL = ?, IDGENERO = ? WHERE IDLIBRO = ?");
                pst.setString(1, nuevoLibro.getIsbn());
                pst.setString(2, nuevoLibro.getTitulo());
                pst.setInt(3, nuevoLibro.getEdicion());
                pst.setInt(4, nuevoLibro.getEditorial().getIdEditorial());
                pst.setInt(5, nuevoLibro.getGenero().getIdGenero());
                pst.setInt(6, nuevoLibro.getIdLibro());
            }

            pst.executeUpdate();

            pst = conn.prepareStatement("DELETE FROM AUTORDELIBRO WHERE IDLIBRO = ?");


            pst.setInt(1, nuevoLibro.getIdLibro());
            pst.executeUpdate();

            for (Autor autor : nuevoLibro.getAutores()) {
                pst = conn.prepareStatement(
                        "INSERT INTO AUTORDELIBRO (IDAUTOR, IDLIBRO) "
                        + "VALUES (?,?)");
                pst.setInt(1, autor.getIdAutor());
                pst.setInt(2, nuevoLibro.getIdLibro());

                pst.executeUpdate();
            }
            conn.commit();
        } catch (FileNotFoundException ex) {
            try {
                conn.rollback();
            } catch (SQLException ex1) {
                throw new ExcepcionDeBD("Hubo un problema al intentar actualizar "
                        + "el registro en la Base de Datos");
            }
            throw new ExcepcionDeBD("No se pudo actualizar la portada del libro");
        } catch (SQLException ex) {
            try {
                conn.rollback();
            } catch (SQLException ex1) {
                throw new ExcepcionDeBD("Hubo un problema al intentar actualizar "
                        + "el registro en la Base de Datos");
            }

            throw new ExcepcionDeBD("No se pudo actualizar el Libro"
                    + " en la Base de Datos");
        } finally {
            try {
                conn.close();
            } catch (SQLException ex) {
                throw new ExcepcionDeBD("No se pudo cerrar correctamente la "
                        + " conexión con la Base de Datos");
            }
        }
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Ejemplar">
    //Estados:
    //(D) Disponible
    //(P) Prestado
    //(B) Baja
    public int registrarEjemplar(Libro libroSeleccionado) throws ExcepcionDeBD {
        int idGenerado = -1;

        dbm = DBManager.getInstancia();
        Connection conn;
        try {
            conn = dbm.getConnection();
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo conseguir una conexión con la Base de Datos");
        }
        try {

            PreparedStatement pst;

            pst = conn.prepareStatement(
                    "INSERT INTO EJEMPLAR (IDLIBRO, ESTADO) "
                    + "VALUES (?,?)", Statement.RETURN_GENERATED_KEYS);
            pst.setInt(1, libroSeleccionado.getIdLibro());
            pst.setString(2, "D");

            pst.executeUpdate();

            ResultSet rs = pst.getGeneratedKeys();

            while (rs.next()) {
                idGenerado = rs.getInt(1);
            }

            rs.close();

        } catch (SQLException ex) {

            throw new ExcepcionDeBD("Hubo un problema al intentar registrar "
                    + "el nuevo Ejemplar en la Base de Datos");

        } finally {
            try {
                conn.close();
            } catch (SQLException ex) {
                throw new ExcepcionDeBD("No se pudo cerrar correctamente la "
                        + " conexión con la Base de Datos");
            }
        }
        return idGenerado;
    }

    public ArrayList<Ejemplar> buscarEjemplaresDisponiblesParaLibro(Libro libroSeleccionado) throws ExcepcionDeBD {
        ArrayList<Ejemplar> coincidencias = new ArrayList<>();
        dbm = DBManager.getInstancia();
        Connection conn;

        try {
            conn = dbm.getConnection();
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo conseguir una conexión con la Base de Datos");
        }

        PreparedStatement pst;

        try {
            pst = conn.prepareStatement("SELECT IDEJEMPLAR, IDLIBRO, ESTADO FROM EJEMPLAR WHERE IDLIBRO = ? AND ESTADO = ?");

            pst.setInt(1, libroSeleccionado.getIdLibro());
            pst.setString (2, "D");

            ResultSet rs = pst.executeQuery();
            Ejemplar ejemplar;
            
            while (rs.next()) {
                
                ejemplar = new Ejemplar(
                        rs.getInt("IDEJEMPLAR"),
                        libroSeleccionado, Ejemplar.EstadoEjemplar.Disponible);
                coincidencias.add(ejemplar);
            }
        } catch (SQLException ex) {
            throw new ExcepcionDeBD("No se pudo acceder a la información de Libros");
        }

        return coincidencias;
    }
    //</editor-fold>
}
